﻿// VsPkg.cs : Implementation of Tortuga_Package
//

using System;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.InteropServices;
using System.ComponentModel.Design;
using Microsoft.Win32;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
using System.Reflection;
using Microsoft.VisualStudio;
using VSSDKAssist.Assets.Helpers;
using EnvDTE;
using System.Collections;
using System.Collections.Generic;
using Tortuga.Core;
using Tortuga.Core.TortoiseCommands;
using System.IO;

namespace ACP.Tortuga_Package
{
    /// <summary>
    /// This is the class that implements the package exposed by this assembly.
    ///
    /// The minimum requirement for a class to be considered a valid package for Visual Studio
    /// is to implement the IVsPackage interface and register itself with the shell.
    /// This package uses the helper classes defined inside the Managed Package Framework (MPF)
    /// to do it: it derives from the Package class that provides the implementation of the 
    /// IVsPackage interface and uses the registration attributes defined in the framework to 
    /// register itself and its components with the shell.
    /// </summary>
    // This attribute tells the registration utility (regpkg.exe) that this class needs
    // to be registered as package.
    [PackageRegistration(UseManagedResourcesOnly = true)]
    // A Visual Studio component can be registered under different regitry roots; for instance
    // when you debug your package you want to register it in the experimental hive. This
    // attribute specifies the registry root to use if no one is provided to regpkg.exe with
    // the /root switch.
    [DefaultRegistryRoot("Software\\Microsoft\\VisualStudio\\8.0")]
    // This attribute is used to register the informations needed to show the this package
    // in the Help/About dialog of Visual Studio.
    [InstalledProductRegistration(false, "#110", "#112", "1.0", IconResourceID = 400)]
    // In order be loaded inside Visual Studio in a machine that has not the VS SDK installed, 
    // package needs to have a valid load key (it can be requested at 
    // http://msdn.microsoft.com/vstudio/extend/). This attributes tells the shell that this 
    // package has a load key embedded in its resources.
    [ProvideLoadKey("Standard", "1.0", "Tortuga", "ACP", 1)]
    // This attribute is needed to let the shell know that this package exposes some menus.
    [ProvideMenuResource(1000, 1)]
    [Guid(GuidList.guidTortuga_PackagePkgString)]
    public sealed class Tortuga_Package : Package
    {
		private EnvDTE._DTE _application = null;
		private TortoiseProcess _tortoiseProc = null;

		private TortoiseProcess TortoiseProc {
			get {
				if (_tortoiseProc == null) _tortoiseProc = new TortoiseProcess();
				return _tortoiseProc;
			}
			set { _tortoiseProc = value; }
		}
		

        /// <summary>
        /// Default constructor of the package.
        /// Inside this method you can place any initialization code that does not require 
        /// any Visual Studio service because at this point the package object is created but 
        /// not sited yet inside Visual Studio environment. The place to do all the other 
        /// initialization is the Initialize method.
        /// </summary>
        public Tortuga_Package()
        {
            Trace.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", this.ToString()));
        }

		public SelectedItemCollection GetSelectedItems() {
			return SelectedItemHelper.GetSelectedItems(_application);
		}


		public string GetSelectedPath() {
			return GetSelectedPath(GetSelectedItems());
		}

		/// <summary>
		/// Theoretically if you use this you have only selected one item.  Maybe do some more checking in the future.
		/// </summary>
		/// <param name="selectedItems"></param>
		/// <returns></returns>
		public string GetSelectedPath(IEnumerable<SelectedItem> selectedItems) {
			List<string> selectedPaths = new SelectedItemCollection(selectedItems).GetSelectedPaths();
			return (selectedPaths.Count > 0) ? selectedPaths[0] : "";
		}

		public List<string> GetSelectedPaths() {
			return GetSelectedItems().GetSelectedPaths();
		}

		/////////////////////////////////////////////////////////////////////////////
        // Overriden Package Implementation
        #region Package Members

        /// <summary>
        /// Initialization of the package; this method is called right after the package is sited, so this is the place
        /// where you can put all the initilaization code that rely on services provided by VisualStudio.
        /// </summary>
        protected override void Initialize()
        {
            Trace.WriteLine (string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this.ToString()));
            base.Initialize();

            // Add our command handlers for menu (commands must exist in the .ctc file)
            OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
			_application = GetService(typeof(EnvDTE._DTE)) as EnvDTE._DTE;
            if ( null != mcs )
            {
				
                // Create the command for the menu item.
                /*CommandID menuCommandID = new CommandID(GuidList.guidTortuga_PackageCmdSet, (int)PkgCmdIDList.cmdidCommit);
                MenuCommand menuItem = new MenuCommand( new EventHandler(MenuItemCallback), menuCommandID );
                mcs.AddCommand( menuItem );*/
				MenuCommand commit = AddCommandHandler(PkgCmdIDList.cmdidCommit, mcs, CommitCallback);
				MenuCommand update = AddCommandHandler(PkgCmdIDList.cmdidUpdate, mcs, UpdateCallback);
				MenuCommand diff = AddCommandHandler(PkgCmdIDList.cmdidDiff, mcs, DiffCallback);
				MenuCommand log = AddCommandHandler(PkgCmdIDList.cmdidLog, mcs, LogCallback);
				MenuCommand revert = AddCommandHandler(PkgCmdIDList.cmdidRevert, mcs, RevertCallback);
				MenuCommand add = AddCommandHandler(PkgCmdIDList.cmdidAdd, mcs, AddCallback);
				MenuCommand lockCmd = AddCommandHandler(PkgCmdIDList.cmdidLock, mcs, LockCallback);
				MenuCommand rename = AddCommandHandler(PkgCmdIDList.cmdidRename, mcs, RenameCallback);
				MenuCommand remove = AddCommandHandler(PkgCmdIDList.cmdidRemove, mcs, RemoveCallback);
				MenuCommand resolve = AddCommandHandler(PkgCmdIDList.cmdidResolve, mcs, ResolveCallback);
				MenuCommand conflictEditor = AddCommandHandler(PkgCmdIDList.cmdidConflictEditor, mcs, ConflictEditorCallback);
				MenuCommand repoBrowser = AddCommandHandler(PkgCmdIDList.cmdidRepoBrowser, mcs, RepoBrowserCallback);
				MenuCommand checkout = AddCommandHandler(PkgCmdIDList.cmdidCheckout, mcs, CheckoutCallback);
				MenuCommand cleanup = AddCommandHandler(PkgCmdIDList.cmdidCleanup, mcs, CleanupCallback);
				MenuCommand export = AddCommandHandler(PkgCmdIDList.cmdidExport, mcs, ExportCallback);
				MenuCommand ignore = AddCommandHandler(PkgCmdIDList.cmdidIgnore, mcs, IgnoreCallback);


						/*
#define cmdidConflictEditor 0x210
#define cmdidRepoBrowser 0x220
#define cmdidCheckout 0x230
#define cmdidCleanup 0x240
#define cmdidExport 0x250
#define cmdidIgnore 0x260*/
								
            }
        }
        #endregion


		#region Callbacks
		private void CommitCallback(object sender, EventArgs e) {

			SelectedItemCollection si = GetSelectedItems();
			bool solution = si.ContainsSolution();

			SelectedItemCollection projs = si.FindProjects();

			//ExecuteTortoiseCommand(new CommitCommand(GetSelectedPaths().ToArray()));
		}

		private void AddCallback(object sender, EventArgs e) {
			ExecuteTortoiseCommand(new AddCommand(GetSelectedPaths().ToArray()));
		}

		private void RemoveCallback(object sender, EventArgs e) {
			ExecuteTortoiseCommand(new RemoveCommand(GetSelectedPaths().ToArray()));
		}
		
		private void RenameCallback(object sender, EventArgs e) {
			ExecuteTortoiseCommand(new RenameCommand(GetSelectedPaths().ToArray()));
		}

		private void ResolveCallback(object sender, EventArgs e) {
			ExecuteTortoiseCommand(new ResolveCommand(GetSelectedPaths().ToArray()));
		}

		private void UpdateCallback(object sender, EventArgs e) {
			// TODO
			// Only one destination can be updated
			ExecuteTortoiseCommand(new UpdateCommand(GetSelectedPath()));
		}

		private void DiffCallback(object sender, EventArgs e) {
			// TODO
			// Only one file can be diffed
			ExecuteTortoiseCommand(new DiffCommand(GetSelectedPath()));

		}

		private void LogCallback(object sender, EventArgs e) {
			// TODO
			// Only one file's log can be viewed
			ExecuteTortoiseCommand(new LogCommand(GetSelectedPath()));
		}

		private void RevertCallback(object sender, EventArgs e) {
			ExecuteTortoiseCommand(new RevertCommand(GetSelectedPaths().ToArray()));
		}

		private void LockCallback(object sender, EventArgs e) {
			ExecuteTortoiseCommand(new LockCommand(GetSelectedPaths().ToArray()));
		}


		private void ConflictEditorCallback(object sender, EventArgs e) {
			// TODO
			// Only one file can be edited
			ExecuteTortoiseCommand(new ConflictEditorCommand(GetSelectedPath()));
		}


		private void RepoBrowserCallback(object sender, EventArgs e) {			
			// TODO - find solution repo URL
			ExecuteTortoiseCommand(new RepoBrowserCommand(GetSolutionDirectory()));
		}

		private void CheckoutCallback(object sender, EventArgs e) {
			// TODO - get solution path, figure out what to use for URL
			string solutionPath = GetSolutionDirectory();
			string url = "";
			ExecuteTortoiseCommand(new CheckoutCommand(solutionPath, url));
		}

		private void CleanupCallback(object sender, EventArgs e) {
			ExecuteTortoiseCommand(new CleanupCommand(GetSolutionDirectory()));
		}

		private void ExportCallback(object sender, EventArgs e) {
			ExecuteTortoiseCommand(new ExportCommand(GetSelectedPath()));
		}

		private void IgnoreCallback(object sender, EventArgs e) {
			ExecuteTortoiseCommand(new IgnoreCommand(GetSelectedPaths().ToArray()));
		}

		private string GetSolutionDirectory() {
			return GetParentDirectory(this._application.Solution.FileName);
		}

		private string GetParentDirectory(string path) {
			return Directory.GetParent(path).FullName;
		}
		


		#endregion

		#region Util

		private static bool IsNull(object o) {
			return (o == null);
		}

		private void ExecuteTortoiseCommand(TortoiseCommand cmd) {
			try {
				TortoiseProc.ExecuteCommand(cmd);
			} catch (Exception ex) {

			}
		}


		private void ShowMessageBox(string message) {
			IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell));
			Guid clsid = Guid.Empty;
			int result;
			uiShell.ShowMessageBox(
					   0,
					   ref clsid,
					   "Tortuga",
					   message,
					   string.Empty,
					   0,
					   OLEMSGBUTTON.OLEMSGBUTTON_OK,
					   OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
					   OLEMSGICON.OLEMSGICON_INFO,
					   0,        // false
					   out result);
		}
		private MenuCommand AddCommandHandler(uint cmdid, OleMenuCommandService menuCommandService, EventHandler callback) {
			return AddCommandHandler((int)cmdid, menuCommandService, callback);
		}

		private MenuCommand AddCommandHandler(int cmdid, OleMenuCommandService menuCommandService, EventHandler callback) {
			return AddCommandHandler(new CommandID(GuidList.guidTortuga_PackageCmdSet, cmdid), menuCommandService, callback);
			
		}

		private MenuCommand AddCommandHandler(CommandID cmdid, OleMenuCommandService menuCommandService, EventHandler callback) {
			MenuCommand menuItem = new MenuCommand(new EventHandler(callback), cmdid);
			menuCommandService.AddCommand(menuItem);
			return menuItem;
		}
		#endregion

	}
}